﻿using System;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using BSU.GraduateWork.LinesIn3D;

namespace BSU.GraduateWork.Visualizer
{
    public partial class MainPage : UserControl, IVectorVisualizerUI
    {
        /// <summary>
        /// Used to slow down the movement
        /// </summary>
        private const double COEF_MOVE = 0.3;
        private const string VECTORS_CHANGE_JS_FUNC = "VV_ChangeVectors";

        private static readonly Brush _AxisDefaultBrush = new SolidColorBrush(Color.FromArgb(0xFF, 0x55, 0x55, 0x55));
        private static readonly Brush _SubAxisDefaultBrush = new SolidColorBrush(Color.FromArgb(0xFF, 0xCC, 0xCC, 0xCC));
        private const double _AxisDefaultLength = 216.0;
        private static readonly Point _AxisDefaultCenter = new Point(240, 280);
        private const double _AxisArrowSize = 10.0;
        private const double _LetterShift = 5.0;
        private const double _LetterWidth = 10.0;
        private const double _LetterHeight = 20.0;
        private const double _VectorFactor = 20.0;
        private const double _VectorLimit = 10.0;




        private bool _isDragging;
        private bool _isOverSliderX;
        private bool _isOverSliderY;
        private bool _isOverSliderZ;
        private Point _mouseLastPoint;
        private string _currentPageUrl;



        private static readonly Color[] Colors =
            new[]
            {
                Color.FromArgb(0xFF,0x00,0x00,0xFF),
                Color.FromArgb(0xFF,0xFF,0x00,0x00),
                Color.FromArgb(0xFF,0x00,0xAA,0x00),
                Color.FromArgb(0xFF,0xAA,0x66,0x00),
                Color.FromArgb(0xFF,0x00,0x66,0xAA),
                Color.FromArgb(0xFF,0xAA,0xAA,0x00),
                Color.FromArgb(0xFF,0x00,0xAA,0xAA),
                Color.FromArgb(0xFF,0x66,0xAA,0x00),
                Color.FromArgb(0xFF,0x00,0xAA,0x66),
                Color.FromArgb(0xFF,0xAA,0x00,0xAA),
                Color.FromArgb(0xAA,0x66,0xAA,0x66),
                Color.FromArgb(0xAA,0x66,0x00,0x66),
                Color.FromArgb(0xAA,0xAA,0x66,0xAA),
                Color.FromArgb(0xAA,0x00,0x00,0x00)
            };

        private int _currentColorIndex;

        public Brush AxisBrush { get { return _AxisDefaultBrush; } }
        public Brush SubAxisBrush { get { return _SubAxisDefaultBrush; } }
        public double AxisLength { get { return _AxisDefaultLength; } }
        public Point AxisCenter { get { return _AxisDefaultCenter; } }
        public double AxisArrowSize { get { return _AxisArrowSize; } }
        public double LetterShift { get { return _LetterShift; } }
        public double LetterWidth { get { return _LetterWidth; } }
        public double LetterHeight { get { return _LetterHeight; } }
        public double VectorFactor { get { return _VectorFactor; } }

        public string CurrentPageUrl
        {
            get { return _currentPageUrl; }
            set
            {
                _currentPageUrl = value;
                var func = HtmlPage.Window.GetProperty(VECTORS_CHANGE_JS_FUNC) as ScriptObject;
                if (func != null)
                {
                    func.InvokeSelf(_currentPageUrl);
                }
            }
        }

        public VectorVisualizer Visualizer { get; private set; }

        public static MainPage Current;


        public MainPage()
        {
            Current = this;

            InitializeComponent();

            Visualizer = new VectorVisualizer(this);

            Visualizer.Lines.ReDrawn += Lines_ReDrawn;

            Visualizer.Initialize();

            MouseLeftButtonDown += Page_MouseLeftButtonDown;
            MouseLeftButtonUp += Page_MouseLeftButtonUp;
            MouseLeave += Page_MouseLeave;
            MouseMove += Page_MouseMove;
        }

        private void Lines_ReDrawn(object sender, EventArgs e)
        {
            if (!_isOverSliderX) SliderX.Value = ((Visualizer.Lines.RotationDegreesX + 180) / 360D) * 10;
            if (!_isOverSliderY) SliderY.Value = ((Visualizer.Lines.RotationDegreesY + 180) / 360D) * 10;
            if (!_isOverSliderZ) SliderZ.Value = ((Visualizer.Lines.RotationDegreesZ + 180) / 360D) * 10;

            DegreesX.Text = Visualizer.Lines.RotationDegreesX.ToString();
            DegreesY.Text = Visualizer.Lines.RotationDegreesY.ToString();
            DegreesZ.Text = Visualizer.Lines.RotationDegreesZ.ToString();
        }

        public void AddLine(Line2D line)
        {
            if (line.HeadUI != null)
            {
                GraphContainer.Children.Add(line.HeadUI);
            }
            GraphContainer.Children.Add(line.LineUI);
        }
        public void RemoveLine(Line2D line)
        {
            if (line.HeadUI != null)
            {
                GraphContainer.Children.Remove(line.HeadUI);
            }
            GraphContainer.Children.Remove(line.LineUI);
        }

        public void ResetColorIndex()
        {
            _currentColorIndex = 0;
        }

        private void Page_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            _isDragging = true;
            _mouseLastPoint = e.GetPosition(GraphContainer);
        }

        private void Page_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            UndoMouseDown();
        }
        private void Page_MouseLeave(object sender, MouseEventArgs e)
        {
            UndoMouseDown();
            _isOverSliderX = _isOverSliderY = _isOverSliderZ = false;
        }

        private void UndoMouseDown()
        {
            _isDragging = false;
        }


        private void Page_MouseMove(object sender, MouseEventArgs e)
        {
            if (!_isDragging)
            {
                return;
            }
            var mousePoint = e.GetPosition(GraphContainer);
            if (e.GetPosition(LayoutRoot).X > 600)
            {
                _isDragging = false;
                return;
            }
            else
            {
                _isOverSliderX = _isOverSliderY = _isOverSliderZ = false;
            }

            Visualizer.MouseMove(
                (mousePoint.X - _mouseLastPoint.X) * COEF_MOVE,
                (mousePoint.Y - _mouseLastPoint.Y) * COEF_MOVE
            );
            _mouseLastPoint = mousePoint;
        }

        private void ResetBtn_Click(object sender, RoutedEventArgs e)
        {
            Visualizer.SetInitialPosition();
        }

        private void DegreesX_LostFocus(object sender, RoutedEventArgs e)
        {
            VerifyAndSetAxisValue(
                    sender as TextBox,
                    (degrees, visualizer) =>
                    {
                        visualizer.Lines.RotateToDegreesAroundX(degrees);
                        Visualizer.Lines.ReDraw();
                        return degrees.ToString();
                    });
        }

        private void DegreesY_LostFocus(object sender, RoutedEventArgs e)
        {
            VerifyAndSetAxisValue(
                    sender as TextBox,
                    (degrees, visualizer) =>
                    {
                        visualizer.Lines.RotateToDegreesAroundY(degrees);
                        Visualizer.Lines.ReDraw();
                        return degrees.ToString();
                    });
        }

        private void DegreesZ_LostFocus(object sender, RoutedEventArgs e)
        {
            VerifyAndSetAxisValue(
                    sender as TextBox,
                    (degrees, visualizer) =>
                    {
                        visualizer.Lines.RotateToDegreesAroundZ(degrees);
                        Visualizer.Lines.ReDraw();
                        return degrees.ToString();
                    });
        }

        private void DegreesX_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                DegreesX_LostFocus(sender, e);
            }
        }

        private void DegreesY_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                DegreesY_LostFocus(sender, e);
            }
        }

        private void DegreesZ_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                DegreesZ_LostFocus(sender, e);
            }
        }



        private void VerifyAndSetAxisValue(TextBox textBox, Func<double, VectorVisualizer, string> func)
        {
            var text = textBox.Text.Trim().Replace(',', '.');
            if (text == String.Empty)
            {
                textBox.Text = func(0, Visualizer);
                textBox.Select(textBox.Text.Length, 0);
                return;
            }
            double degrees;
            if (Double.TryParse(text, out degrees))
            {
                degrees = degrees % 360;
                textBox.Text = func(degrees, Visualizer);
                textBox.Select(textBox.Text.Length, 0);
                return;
            }
            HtmlPage.Window.Alert(SR.PleaseEnterNumericValue);
            textBox.Text = func(0, Visualizer);
            textBox.Select(textBox.Text.Length, 0);
        }

        private void VerifyVectorValue(TextBox textBox)
        {
            var text = textBox.Text.Trim().Replace('.', ',');
            if (text == "-")
            {
                return;
            }
            if (text == String.Empty)
            {
                textBox.Text = 0.ToString();
                return;
            }
            double value;
            if (Double.TryParse(text, out value))
            {
                if (value < _VectorLimit * -1 || value > _VectorLimit)
                {
                    HtmlPage.Window.Alert(SR.TheValueMustBeBetween.Args(_VectorLimit));
                    textBox.Text = (value > 0 ? _VectorLimit : _VectorLimit * -1).ToString();
                }
                return;
            }
            HtmlPage.Window.Alert(SR.PleaseEnterNumericValue);
            textBox.Text = 0.ToString();
        }

        private void SliderX_MouseEnter(object sender, EventArgs e)
        {
            _isOverSliderX = true;
        }

        private void SliderY_MouseEnter(object sender, EventArgs e)
        {
            _isOverSliderY = true;
        }

        private void SliderZ_MouseEnter(object sender, EventArgs e)
        {
            _isOverSliderZ = true;
        }



        private void SliderX_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            var slider = (Slider)sender;
            if (!_isOverSliderX || !slider.IsFocused)
            {
                return;
            }
            Visualizer.Lines.ShiftDegreesAroundX(((e.NewValue / 10) * 360 - 180) - Visualizer.Lines.RotationDegreesX);
            Visualizer.Lines.ReDraw();
        }
        private void SliderY_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            var slider = (Slider)sender;
            if (!_isOverSliderY || !slider.IsFocused)
            {
                return;
            }
            Visualizer.Lines.ShiftDegreesAroundY(((e.NewValue / 10) * 360 - 180) - Visualizer.Lines.RotationDegreesY);
            Visualizer.Lines.ReDraw();
        }
        private void SliderZ_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            var slider = (Slider)sender;
            if (!_isOverSliderZ || !slider.IsFocused)
            {
                return;
            }
            Visualizer.Lines.ShiftDegreesAroundZ(((e.NewValue / 10) * 360 - 180) - Visualizer.Lines.RotationDegreesZ);
            Visualizer.Lines.ReDraw();
        }

        private void Vector_TextChanged(object sender, EventArgs e)
        {
            VerifyVectorValue(sender as TextBox);
        }

        private void Vector_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
            {
                Vector_TextChanged(sender, e);
            }
        }

        public Brush NextColor
        {
            get
            {
                var brush = new SolidColorBrush(Colors[_currentColorIndex]);
                //_currentColorIndex = (_currentColorIndex == (Colors.Length - 1)) ? 0 : _currentColorIndex + 1;
                //ColorRectangle.Fill = new SolidColorBrush(Colors[_currentColorIndex]);
                return brush;
            }
        }

        private void AddVector(VectorUI vector)
        {
            Visualizer.AddVector(vector);
        }
    }

}
